/*
 * world.h
 *
 *  Created on: June 27, 2011
 *      Authors: Lane Aasen, Nikholas Gaffney, Michael Rosenberger, Dylan Swiggett
 */

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "boid.h"
#include "vector3D.h"
#include "boidType.h"

#ifndef WORLD_H_
#define WORLD_H_

/*
 * A node is an abstract element of the linked list which contains a boid and a
 * pointer to the next element in the linked list.
 * If the pointer is NULL, then it is the last element in the list.
 */
typedef struct Node {
	struct Node* next;
	Boid value;
} Node;

/*
 * A world is a container that holds a linked list (or rather, its root pointer),
 * a vector for gravity in the world, an air friction coefficient, and the bounding
 * coordinates for the world.
 */

typedef struct {
	Node* root;
	Vector3D gravity;
	double afCoefficient;
	double xMin, xMax, yMin, yMax, zMin, zMax;
} World;

/*
 * Takes a pointer to a world and a boid, and inserts the given boid at the first
 * position in the world's linked list of boids.
 */

void addBoidToWorld(World* ptrWorld, Boid toAdd);

/*
 * Takes a pointer to a world and the parameters to initBoid, creates a boid with
 * the given parameters, and adds it to the world. Has the advantage of rolling 2
 * commonly combined operations (creating a boid then adding it to a world) into one.
 */

void createBoidAndAddToWorld(World* ptrWorld, Vector3D location, Vector3D velocity, double volume, BoidType* type);

/*
 * Initializes a brand new world, taking a gravity vector, an air friction coefficient,
 * and the bounding coordinates for the world.
 */

World initWorld(Vector3D gravity, double afCoefficient, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax);

/*
 * Takes a pointer to a world and a a pointer to a boid, and then does the following,
 * in order:
 * 1. Updates the boid's velocity according to the world's gravity
 * 2. Updates the boid's velocity according to the world's air friction
 * 3. Updates the boid's position according to its current velocity
 * 4. Updates the boid's position and velocity according to the world's bounds.
 * 	  If the boid is out of the bounds of the world, its position is set to the
 *    corresponding bound of the world, and its velocity in that direction is
 *    reversed.
 *
 * Named isolated because it does not do any updating which relates to other boids;
 * for that see findAndUpdateNeighbors
 */

void isolatedUpdateBoid(World* world, Boid* boid);

/*
 * Alters the velocity vector of the sailor so that it moves towards the siren. Assumes that sailor is within siren's attractive radius
 */

void attrBoid(Boid* siren, Boid* sailor);

/*
 * Alters the velocity vector of the sailor so that it moves away from the siren. Assumes that sailor is within siren's repulsive radius
 */

void repelBoid(Boid* siren, Boid* sailor);

/*
 * Goes through the linked list of the given world, and if the current boid is within the given boid's update
 * radius, it attracts and repels it.
 *
 * NOTE: as soon as the rTree is implemented, this function must be deprecated
 */

void findAndUpdateNeighbors(World* ptrWorld, Boid* ptrBoid);

/*
 * Ticks a world one step into the future, doing neighbor-wise and isolated updating of all boids.
 * Does all of the following, in order (some of these are listed in other functions because this function
 * builds on those):
 *
 * 1. Find the neighbors of each boid, and attracts/repels them (modifies their velocities)
 * 2. Updates boids' velocities based on gravity, then air friction
 * 3. Updates boids' positions based on their velocities
 * 4. Bounds each boid based on its position, modifying its position and velocity as needed
 *
 * NOTE: as soon as the rTree is implemented, this function must be modified/deprecated
 *
 */

void tick(World* ptrWorld);

#endif
